package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"

	"github.com/jmoiron/sqlx"

	"agentdesign/config"
	"agentdesign/database"
)

const (
	MigrationDirectoryPath = "./migrations"
)

func main() {
	config, err := config.LoadConfig()

	if err != nil {
		log.Fatalf("failed to load configuration: %v", err)
	}

	connection, err := database.InitializeMySQL(&config.Database)

	if err != nil {
		log.Fatalf("failed to initialize MySQL: %v", err)
	}

	defer connection.Close()

	if err := processMigrations(connection); err != nil {
		log.Fatalf("failed to process migrations: %v", err)
	}

	fmt.Println("migrations completed successfully")
}

// processMigrations processes the migrations.
func processMigrations(connection *sqlx.DB) error {
	err := ensureMigrationTable(connection)

	if err != nil {
		log.Fatalf("failed to ensure migration table: %v", err)
	}

	dir, err := os.ReadDir(MigrationDirectoryPath)

	if err != nil {
		log.Fatalf("failed to read migration directory: %v", err)
	}

	for _, file := range dir {
		if file.IsDir() {
			fmt.Println("skipping directory:", file.Name())
			continue
		}

		if filepath.Ext(file.Name()) != ".sql" {
			fmt.Println("skipping non-SQL file:", file.Name())
			continue
		}

		executed, err := isExecuted(connection, file.Name())
		if err != nil {
			return err
		}
		if executed {
			fmt.Println("migration file already executed:", file.Name())
			continue
		}

		content, err := os.ReadFile(filepath.Join(MigrationDirectoryPath, file.Name()))
		if err != nil {
			return err
		}

		tx, err := connection.Begin()
		if err != nil {
			return err
		}

		_, err = tx.Exec(string(content))
		if err != nil {
			tx.Rollback()
			return err
		}

		_, err = tx.Exec("INSERT INTO migrations (filename) VALUES (?)", file.Name())
		if err != nil {
			return err
		}

		err = tx.Commit()
		if err != nil {
			return err
		}
	}

	return nil
}

// ensureMigrationTable ensures the migration table exists.
func ensureMigrationTable(connection *sqlx.DB) error {
	sentence := `
	CREATE TABLE IF NOT EXISTS migrations (
		id INT AUTO_INCREMENT PRIMARY KEY,
		filename VARCHAR(255) NOT NULL,
		applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
	)
	`

	_, err := connection.Exec(sentence)
	return err
}

// isExecuted checks if the migration has been executed.
func isExecuted(connection *sqlx.DB, filename string) (bool, error) {
	sentence := `
	SELECT COUNT(*) FROM migrations WHERE filename = ?
	`

	var count int
	err := connection.Get(&count, sentence, filename)
	if err != nil {
		return false, err
	}

	return count > 0, nil
}
